package org.rency.crawler.fetch.handler.impl;

import java.time.LocalDateTime;
import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils;
import org.rency.crawler.common.enums.ReturnCode;
import org.rency.crawler.common.exception.CrawlerException;
import org.rency.crawler.common.helper.GeneratorHelper;
import org.rency.crawler.domain.FetchHost;
import org.rency.crawler.domain.FetchResponse;
import org.rency.crawler.domain.http.FetchHttpRequest;
import org.rency.crawler.domain.http.FetchHttpResponse;
import org.rency.crawler.domain.state.FetchStatus;
import org.rency.crawler.fetch.handler.AbstractFetchHandler;
import org.rency.crawler.fetch.helper.BuilderHelper;
import org.rency.crawler.fetch.helper.FetchCarrier;
import org.rency.crawler.fetch.repository.FetchExtRepository;
import org.rency.crawler.fetch.repository.FetchedQueueRepository;
import org.rency.crawler.fetch.repository.HostQueueRepository;
import org.rency.crawler.fetch.repository.MetaResourceRepository;
import org.rency.crawler.fetch.service.http.HttpService;
import org.springframework.stereotype.Component;

/**
 * 描述: ${TODO}<br>
 * 最近修改时间:2017/11/22 11:50<br>
 *
 * @author CaiyuRen
 * @version V1.0
 * @since 2017/11/22 11:50
 */
@Component
public class FetchHttpHandler extends AbstractFetchHandler {

  @Resource
  private HttpService             httpService;

  @Resource
  private HostQueueRepository     hostQueueRepository;

  @Resource
  private FetchedQueueRepository  fetchedQueueRepository;

  @Resource
  private FetchExtRepository      fetchExtRepository;

  @Resource
  private MetaResourceRepository  metaResourceRepository;

  @Override
  protected String getHandlerName() {
    return "HTTP请求";
  }

  @Override
  protected void onHandler(FetchCarrier carrier) throws CrawlerException {
    FetchHttpRequest httpRequest = this.build(carrier);
    carrier.setHttpRequest(httpRequest);
    FetchHttpResponse httpResponse = this.send(carrier);
    this.updateFetchExtension(carrier);
    this.updateHost(carrier);

    if(httpResponse == null){
      carrier.getFetchState().setFsStatus(FetchStatus.EXCEPTION);
      //访问失败,从已抓取队列中移除
      fetchedQueueRepository.delete(carrier.getRequest().getFetchNo());
      return;
    }

    if(!httpResponse.isNeedParse()){
      logger.debug("HTTP返回无需解析,状态码:{},{}",httpResponse.getStatusCode(),carrier.getLogPrefix());
      carrier.setResponse(FetchResponse.fail(ReturnCode.HTTP_NEEDNT_PARSE));
      carrier.getFetchState().setFsStatus(FetchStatus.FAILED);
      return;
    }

    if(ReturnCode.HTTP_RETRY_TIMES_OUT == ReturnCode.get(carrier.getResponse().getReturnCode())){
      logger.debug("HTTP返回状态码:{},{}",httpResponse.getStatusCode(),carrier.getLogPrefix());
      carrier.getFetchState().setFsStatus(FetchStatus.FAILED);
      return;
    }

    carrier.setHttpResponse(httpResponse);
    //设置状态机
    carrier.getFetchState().setFsStatus(FetchStatus.SUCCESS);
  }

  private FetchHttpResponse send(FetchCarrier carrier) throws CrawlerException{
    FetchHttpResponse httpResponse = this.httpService.submit(carrier.getHttpRequest());
    //判断是否需要重试,且重试次数小于最大重试次数
    if(httpResponse.isNeedRetry()) {
      if (carrier.getExtension().getRetryTimes() < carrier.getExtension().getMaxRetryTimes()) {
        carrier.getExtension().addRetryTimes();
        logger.debug("HTTP请求重试[{}], {}.", carrier.getExtension().getRetryTimes(), carrier.getLogPrefix());
        httpResponse = this.send(carrier);
      } else {
        carrier.setResponse(FetchResponse.fail(ReturnCode.HTTP_RETRY_TIMES_OUT, carrier.getExtension().getRetryTimes() + ""));
      }
    }
    return httpResponse;
  }

  private FetchHttpRequest build(FetchCarrier carrier){
    FetchHttpRequest request = new FetchHttpRequest();
    request.setHost(carrier.getRequest().getHostAddr().trim());
    request.setHttpMethod(carrier.getRequest().getHttpMethod());
    request.setParameter(carrier.getRequest().getParameter());
    request.setIdentity(carrier.getRequest().getFetchNo());
    request.setUrl(carrier.getRequest().getFetchUri().trim());
    return request;
  }

  /**
   * 更新域名
   * @param carrier
   */
  private void updateHost(FetchCarrier carrier){
    if(StringUtils.isBlank(carrier.getRequest().getFetchHost())){
      //hostName在请求时已经校验不可为空
      carrier.getRequest().setFetchHost(GeneratorHelper.genHashCode(carrier.getRequest().getHostAddr()));
    }

    //TODO 减少获取域名IP地址消耗,如果缓存有则直接使用
    FetchHost orgiHost = hostQueueRepository.get(carrier.getRequest().getFetchHost());
    if(orgiHost == null){
      Long intervalTime = metaResourceRepository.getFetchIntervalTime();
      FetchHost domain = BuilderHelper.build(carrier.getRequest().getFetchHost(),null,carrier.getRequest().getHostAddr(),intervalTime,0L);
      hostQueueRepository.save(domain);
    }else{
      orgiHost.setLastedFetchTime(LocalDateTime.now());
      hostQueueRepository.update(orgiHost);
    }
  }

  /**
   * 更新抓取扩展
   * @param carrier
   */
  private void updateFetchExtension(FetchCarrier carrier){
    carrier.getExtension().setLastedFetchTime(LocalDateTime.now());
    fetchExtRepository.update(carrier.getRequest().getFetchNo(),carrier.getExtension());
  }
}
